﻿package engine.game {
	
	import engine.base.sim.Sim;
	import engine.base.sim.SimObject;
	import flash.display.Sprite;
	import flash.geom.Rectangle;
	import flash.display.BitmapData;
	import flash.display.Bitmap;
	import flash.geom.Point;
	import engine.base.SceneObject;
	import engine.game.world.Map;

	/**
	 * This class represents the camera within the game, the camera loads the visuals into its display for the
	 * user to see.
	 * @author Jon Smelquist
	 */
	public class Camera extends Sprite{
		
		private static const _WIDTH:int = 672;
		private static const _HEIGHT:int = 512;
		private static var _instance:Camera;
		private static var _allowInstantiation:Boolean = false;
		/**
		 * Method to return the camera instance if one exists,
		 * and if it does not exist we create one.
		 * @return _instance Camera object instance.
		 */
		public static function getInstance():Camera {
			if (_instance == null) {
				_allowInstantiation = true;
				_instance = new Camera();
				_allowInstantiation = false;
			}
			return _instance;
		}

		/*
		 * VARIABLE DEFINITIONS
		 */
		private var _rect:Rectangle;
		private var _display:BitmapData;
		
	   /**
		* Constructs a camera object, with the specified size.
		* 
		* @param cameraSize The size in 2 dimensions of the camera surface.
		*/
		public function Camera() {
			if (!_allowInstantiation)
				throw new Error("This class cannot be instantiated! Use getInstance() instead.");
			_rect = new Rectangle(0, 0, _WIDTH, _HEIGHT);
			_display = new BitmapData(_WIDTH, _HEIGHT, false, 0xFFFFFFFF);
			addChild( new Bitmap( _display ) );
		}
		
		public function get rect():Rectangle
		{
			return _rect;
		}
		
		public function clearScene():void {
			_display.fillRect(_rect, 0xFFFFFFFF);
		}
		
		public function lockCanvas():void {
			_display.lock();
		}
		
		public function unlockCanvas():void {
			_display.unlock();
		}
		
	   /**
		* Loads the viewport with the visual data to represent the current frame
		* of visual information. It draws the base tiles, with their tile image
		* data, followed by the player and npc graphics and lastly the overlay 
		* information for each tile.
		*/
		public function render(object:Object):void
		{
			if (object is SceneObject)
			{
				object.draw(_display, _rect);
			}
			else if (object is Array) {
				
				for each (var obj:SceneObject in object)
				{
					obj.draw(_display, _rect);
				}
			}
		}
		
		/**
		 * Binds the camera object to the stage.
		 */
		public function bind(view:Sprite):void {
			view.addChild( _instance );
		}
		
		/**
		* Reset the position of the camera, to x=0, y=0
		*/
		public function resetCameraPosition():void {
			_rect.x = 0;
			_rect.y = 0;
		}
		
		/**
		 * Align the camera with the map in case it
		 * exceeded the dimensions.
		 */
		public function alignCamera(obj:SceneObject = null):void {
			
			// if we want to center the camera around a Scene Object
			if (obj != null) {
				_rect.x = obj.position.x - (_rect.width * 0.5);
				_rect.y = obj.position.y - (_rect.height * 0.5);
			}
			
			if (_rect.x < 0)
				_rect.x = 0;
			if (_rect.y < 0)
				_rect.y = 0;
			
			// Grab our objects from the static object manager class
			var map:Map = Sim.findObject("CurrentMap") as Map;
			
			if ((_rect.x + _rect.width) > (map.width*32))
			{
				_rect.x -= (_rect.x + _rect.width - (map.width * 32));
			}
			
			if ((_rect.y +_rect.height) > (map.height*32))
			{
				_rect.y -= (_rect.y + _rect.height - (map.height * 32));
			}
		}
		
	}
		
	
}